Skip to content

Add non-blocking TryBeginInvoke and clarify the realtime threading model#13

Merged
matt-edmondson merged 2 commits into
mainfrom
claude/vst-plugin-upstream-djlud9
Jun 9, 2026
Merged

Add non-blocking TryBeginInvoke and clarify the realtime threading model#13
matt-edmondson merged 2 commits into
mainfrom
claude/vst-plugin-upstream-djlud9

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Summary

Implements upstream roadmap item #4 from the .NET VST3 effects host plan: clarify Invoker's realtime story and add a non-blocking, allocation-free marshalling path for non-realtime producers.

TryBeginInvoke(Action)

A fire-and-forget counterpart to Invoke/InvokeAsync:

  • Non-blocking and allocation-free — no Task is created and the caller never blocks waiting for the owner thread to pump.
  • Returns false when the bounded queue is full (the action is dropped) rather than growing unboundedly — predictable memory behaviour.
  • Runs immediately when called from the owner thread; otherwise queued and drained in FIFO order by DoInvokes, alongside the existing Task queue.
  • New Invoker(int beginInvokeCapacity) constructor sizes the queue (default 1024).

BoundedMpscQueue<T> (internal)

A bounded, lock-free queue implementing Dmitry Vyukov's bounded MPMC algorithm (per-cell sequence numbers, single CAS per op). Safe for any number of concurrent producers; pre-allocates its cells and allocates nothing per enqueue/dequeue.

Documentation

Adds an XML-doc threading section making explicit that:

  • Invoker marshals work onto the owner thread; it doesn't make arbitrary code thread-safe.
  • The blocking/async paths allocate a Task and may block, so they must never be called from a hard real-time audio thread. Audio→UI telemetry should flow through a dedicated SPSC ring buffer (see the companion Containers PR) rather than the invoker.

Testing

Added TryBeginInvokeTests: null-guard, immediate owner-thread execution, cross-thread queue-until-pump, FIFO ordering, full-queue rejection, and a 4-producer × 10k concurrent delivery test. Full suite: 16/16 passing locally (net10.0).

Note: the local sandbox's .NET SDK (10.0.108) predates the Roslyn the pinned ktsu.Sdk analyzers (2.8.0) require, so tests were run via the standard MSTest runner against net10.0. CI runs the full multi-target build with analyzers and style enforcement.

🤖 Part of the ktsu VST plugin upstream-enablement work.

https://claude.ai/code/session_01JQ3bQMuSYuumAnQZaYUKP7


Generated by Claude Code

claude added 2 commits June 9, 2026 03:05
Adds the realtime-oriented invoker work from the .NET VST3 effects host
plan (upstream roadmap item #4):

- TryBeginInvoke(Action): a non-blocking, allocation-free, fire-and-forget
  path that marshals work onto the owner thread. Backed by a new bounded,
  lock-free multi-producer queue (Dmitry Vyukov's bounded MPMC algorithm)
  so producers neither block nor allocate; returns false when the bounded
  queue is full instead of growing unboundedly. Drained in FIFO order by
  DoInvokes alongside the existing Task queue. Runs immediately when called
  on the owner thread.

- New Invoker(int beginInvokeCapacity) constructor to size the queue.

- XML-doc clarification that Invoker is owner-thread-oriented and that the
  blocking/async paths (which allocate a Task and may block) must never be
  called from a hard real-time audio thread; audio->UI telemetry should use
  a dedicated SPSC ring buffer instead.

Includes MSTest coverage: immediate owner-thread execution, cross-thread
queueing, FIFO ordering, full-queue rejection, and a concurrent
multi-producer delivery test.
CI's code-style analyzers (which the local sandbox SDK cannot load) flag the
explicit capacity constructor as IDE0290. Convert to a primary constructor
taking beginInvokeCapacity, with the parameterless constructor delegating to
it via the default capacity. Behaviour is unchanged.
@matt-edmondson matt-edmondson merged commit 78c44be into main Jun 9, 2026
1 check passed
@matt-edmondson matt-edmondson deleted the claude/vst-plugin-upstream-djlud9 branch June 9, 2026 03:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants